//#########################################################################
//                              WackiEngie
//           Copyright (c) 2014 Marc Wacker. All rights reserved.
//#########################################################################

#pragma once

//#include "WeCorePrerequisites.h"
//#include "
#include "WeModule.h"
#include "WeEvent.h"
#include "WeInputEvents.h"
#include "WeInputDeviceHandler.h"
#include "WeVector2.h"

namespace WackiEngine
{



	class Input : public Module<Input>
	{
		struct KeyState
		{
			KeyState()
			: isDown(false), lastDown(0.0f), changedThisFrame(false)
			{ }

			// is this key down
			bool	isDown;
			// last down timestamp
			double	lastDown;	
			// did the state change this frame?
			bool	changedThisFrame;
		};


		// TODO: put this following description about device indices elsewhere
		// Device data for a single device, at the moment standard device indices are as follows:
		// 0 = mouse + keyboard, 1-n = gamepads
		// TODO: a problem from the above comes if we support XInput, which supports up to 4 xbox controllers
		//		and add joystick support on top of that
		//		we need to add a way to let DeviceInputHandlers know on what index they should start with their events!
		struct DeviceData
		{
			DeviceData()
			{
				// VS2013 doesn't support initializer lists for class member arrays... wow..., so we have to resort to this
				for(int32 i = 0; i < KC_Count; ++i) 
					axes[i] = 0.0f;
			}

			KeyState keys[KC_Count];
			// the KeyCode enum holds buttons AND axes, so most of the data in this array is not needed 
			// TODO: do we want to change that? can we?
			float axes[KC_Count];
		};

	public:
		Input();
		~Input();

		// TODO: add signature for most of these events, provide containers that hold event data
		// TODO: add description to most of this
		Event<void(const KeyEvent&)> keyInput;
		Event<void(const CharInputEvent&)> characterInput;

		Event<void(const PointerEvent&)> mouseMove;
		Event<void(const PointerEvent&)> mouseDown;
		Event<void(const PointerEvent&)> mouseUp;
		Event<void(const PointerEvent&)> mouseDoubleClick;
		Event<void(const PointerEvent&)> scrollWheel;

		// updates connected devices and fires event
		void	update();

		float	getAxis(KeyCode axis, uint32 deviceId = 0) const;
		bool	getKey(KeyCode key, uint32 deviceId = 0) const;
		bool	getKeyDown(KeyCode key, uint32 deviceId = 0) const;
		bool	getKeyUp(KeyCode key, uint32 deviceId = 0) const;

		float	getMouseX() const { return _mousePos.x; }
		float	getMouseY() const { return _mousePos.y; }

		void registerInputDeviceHandler(std::shared_ptr<InputDeviceHandler> idh);


	private:
		// holds connected devices
		Vector<DeviceData>		_devices;
		Set<std::shared_ptr<InputDeviceHandler>> _deviceHandlers;
		
		// delay after initial keypress before sending repeat events
		float _keyRepeatDelta;

		// flags for keyboard modifiers
		int32 _modifierState;

		// mouse state
		Vector2f _mousePos;
		Vector2f _mousePrevPos;

		// event signal connections // TODO: is this needed?
		EventHandle mouseMoveCon;
		EventHandle mouseDownCon;
		EventHandle mouseUpCon;
		EventHandle mouseDoubleClickCon;
		EventHandle mouseWheelCon;
		EventHandle charInputCon;
		EventHandle keyboardDownCon;
		EventHandle keyboardUpCon;


		// callbacks for general input devices
		void	onKeyDown(uint32 deviceId, KeyCode keyCode);
		void	onKeyUp(uint32 deviceId, KeyCode keyCode);
		void	onAxisMoved(uint32 deviceId, float value, KeyCode keyCode);

		// Platform (OS) callbacks
		void	onMouseMove(const PointerEvent&);
		void	onMouseDown(const PointerEvent&);
		void	onMouseUp(const PointerEvent&);
		void	onMouseDoubleClick(const PointerEvent&);
		void	onMouseWheel(const PointerEvent&);
		void	onCharInput(uint32 character);
		void	onKeyboardDown(KeyCode keyCode);
		void	onKeyboardUp(KeyCode keyCode);
	};

	Input& gInput();

}